#!/usr/bin/env node

/**
 * 测试脚本：批量调用 OpsClient.appEnv 获取 scm 地址，并按业务分组打印
 *
 * 运行前确保已执行过 nb 初始化，并在全局配置中写入 ops_user。
 *   node test/appEnvScm.js [--verbose]
 */

import process from 'process';
import {opsClient} from '../utils/OpsClient.js';
import {StrUtil} from '../utils/StrUtil.js';
import {createLogger} from '../utils/Logger.js';
import {fetchUserOpsToken} from "../utils/OpsUser.js";
import {getGlobalOpsFile} from "../utils/OpsFile.js";

const logger = createLogger('APP_ENV');

/**
 * 分组的业务应用列表
 * @type {Map<string, string[]>}
 */
const GROUPED_APPS = new Map([
    ['基金', [
        'hs-fund-admin',
        'hs-fund-gaoteng-sdk',
        'hs-fund-interface',
        'hs-fund-service',
        'hs-fund-szt',
        'hs-fund-task',
        'hs-fund-yunfeng-sdk',
        'hs-h5-fund',
        'hs-fund-ows-admin'
    ]],
    ['债券', [
        'hs-h5-bond',
        'hs-bond-yield',
        'hs-bond-task',
        'hs-bond-service',
        'hs-bond-pro',
        'hs-bond-interface',
        'hs-bond-admin'
    ]],
    ['pro', [
        'oms-gateway',
        'oms-interface',
        'oms-manager',
        'oms-risk-manager',
        'oms-service'
    ]],
    ['pro模拟盘', [
        'oms-simulation-gateway',
        'oms-simulation-interface',
        'oms-simulation-manager',
        'oms-simulation-service'
    ]],
    ['Fcn', [
        'hs-sn-service',
        'hs-sn-admin'
    ]]
]);

/**
 * 从 appEnv 返回值中提取 SSH Git 地址
 * @param {object} appData
 * @returns {string}
 */
function resolveSshUrl(appData) {
    if (!appData) {
        return '';
    }
    const {scm} = appData;
    if (typeof scm === 'string') {
        return StrUtil.toSshUrl(scm);
    }
    if (scm && typeof scm === 'object') {
        const candidateKeys = ['ssh', 'git', 'url', 'http', 'https'];
        for (const key of candidateKeys) {
            if (StrUtil.hasValue(scm, key)) {
                return StrUtil.toSshUrl(scm[key]);
            }
        }
    }
    return '';
}

/**
 * 打印最终的分组结果，格式参考 OPSConstant.NB_CLONE_ALIAS_MAP
 * @param {Map<string, string[]>} groupedUrls
 */
function printGroupedUrls(groupedUrls) {
    console.log('\n================ SCM 汇总 ================');
    for (const [groupName, urls] of groupedUrls.entries()) {
        console.log(`'${groupName}': [`);
        if (!urls.length) {
            console.log('    // 未获取到 scm 地址');
        } else {
            urls.forEach((url, index) => {
                const suffix = index === urls.length - 1 ? '' : ',';
                console.log(`    '${url}'${suffix}`);
            });
        }
        console.log('],\n');
    }
}

/**
 * 为给定应用名生成可能的候选名称
 * 处理 - 和 _ 互换，以及 service/server 互换
 * @param {string} appName
 * @returns {string[]}
 */
function buildCandidateNames(appName) {
    const variants = new Set();
    const queue = [appName];

    const enqueue = (name) => {
        if (!name || variants.has(name)) {
            return;
        }
        queue.push(name);
    };

    while (queue.length > 0) {
        const current = queue.shift();
        if (variants.has(current)) {
            continue;
        }
        variants.add(current);

        if (current.includes('-')) {
            enqueue(current.replace(/-/g, '_'));
        }
        if (current.includes('_')) {
            enqueue(current.replace(/_/g, '-'));
        }
        if (current.endsWith('-service')) {
            enqueue(current.replace(/-service$/, '-server'));
        }
        if (current.endsWith('_service')) {
            enqueue(current.replace(/_service$/, '_server'));
        }
        if (current.endsWith('-server')) {
            enqueue(current.replace(/-server$/, '-service'));
        }
        if (current.endsWith('_server')) {
            enqueue(current.replace(/_server$/, '_service'));
        }
    }

    return Array.from(variants);
}

async function main() {
    const globalOpsFile = getGlobalOpsFile();
    const opsUser = globalOpsFile.read(('ops_user'));
    if (!opsUser) {
        logger.error('未在全局配置中读取到 ops_user，请先执行 nb init 或手动配置。');
        process.exitCode = 1;
        return;
    }

    let token;
    try {
        token = await fetchUserOpsToken(opsUser);
    } catch (error) {
        logger.error(`读取用户 ${opsUser} 的 token 失败: ${error.message}`);
        process.exitCode = 1;
        return;
    }

    const verbose = process.argv.includes('--verbose');
    const client = opsClient(token, verbose);
    const groupedUrls = new Map();

    for (const [groupName, apps] of GROUPED_APPS.entries()) {
        const urls = [];
        for (const appName of apps) {
            const candidates = buildCandidateNames(appName);
            let resolvedUrl = '';
            let resolvedName = '';
            let lastError = null;

            for (let i = 0; i < candidates.length; i++) {
                const candidate = candidates[i];
                const isLastAttempt = i === candidates.length - 1;
                try {
                    const appData = await client.appEnv(candidate);
                    const sshUrl = resolveSshUrl(appData);
                    if (sshUrl) {
                        resolvedUrl = sshUrl;
                        resolvedName = candidate;
                    } else {
                        logger.warn(`[${groupName}] ${candidate} 未找到 scm 地址，原始数据: ${JSON.stringify(appData?.scm ?? {})}`);
                    }
                    if (resolvedUrl) {
                        break;
                    }
                } catch (error) {
                    lastError = error;
                    if (!isLastAttempt) {
                        logger.warn(`[${groupName}] ${candidate} 请求失败: ${error.message}，尝试其他别名...`);
                    }
                }
            }

            if (resolvedUrl) {
                urls.push(resolvedUrl);
                const aliasInfo = resolvedName !== appName ? ` (${resolvedName})` : '';
                logger.success(`[${groupName}] ${appName}${aliasInfo} -> ${resolvedUrl}`);
            } else if (lastError) {
                logger.error(`[${groupName}] ${appName} 请求失败: ${lastError.message}`);
            } else {
                logger.warn(`[${groupName}] ${appName} 所有别名均未找到有效 scm，请确认应用名称。`);
            }
        }
        // 去重并保持原有顺序
        const uniqueUrls = Array.from(new Set(urls));
        groupedUrls.set(groupName, uniqueUrls);
    }

    printGroupedUrls(groupedUrls);
}

main().catch(error => {
    logger.error(`脚本执行失败: ${error.message}`);
    process.exitCode = 1;
});
